﻿using System.Windows;

namespace Black.SurfaceToolkit.Converters
{
    /// <summary>
    /// Applique la transformation affine spécifiée.
    /// </summary>
    public class AffineFunctionConverter : FunctionMappingConverter
    {
        #region Accesseurs

        /// <summary>
        /// Obtient ou définit le point 1.
        /// </summary>
        public Point P1
        {
            get
            {
                return (new Point(this.X1, this.m_dY1));
            }
            set
            {
                if (this.P1 != value)
                {
                    this.X1 = value.X;
                    this.m_dY1 = value.Y;
                    this.OnControlPointsChanged();
                }
            }
        }

        /// <summary>
        /// Obtient ou définit le point 2.
        /// </summary>
        public Point P2
        {
            get
            {
                return (new Point(this.X2, this.m_dY2));
            }
            set
            {
                if (this.P2 != value)
                {
                    this.X2 = value.X;
                    this.m_dY2 = value.Y;
                    this.OnControlPointsChanged();
                }
            }
        }

        /// <summary>
        /// Obtient la pente de la fonction.
        /// </summary>
        public double Slope
        {
            get
            {
                return (this.m_dSlope);
            }
        }

        /// <summary>
        /// Obtient ou définit l'ordonnée du point 1.
        /// </summary>
        public double Y1
        {
            get
            {
                return (this.m_dY1);
            }
            set
            {
                if (this.m_dY1 != value)
                {
                    this.m_dY1 = value;
                    this.OnControlPointsChanged();
                }
            }
        }

        /// <summary>
        /// Obtient ou définit l'ordonnée du point 2.
        /// </summary>
        public double Y2
        {
            get
            {
                return (this.m_dY2);
            }
            set
            {
                if (this.m_dY2 != value)
                {
                    this.m_dY2 = value;
                    this.OnControlPointsChanged();
                }
            }
        }

        /// <summary>
        /// Obtient l'image de l'origine.
        /// </summary>
        public double YOrigin
        {
            get
            {
                return (this.m_dYOrigin);
            }
        }

        #endregion

        #region Variables d'instance

        private double m_dY1;
        private double m_dY2;

        private double m_dSlope;
        private double m_dYOrigin;

        #endregion

        #region Constructeurs

        /// <summary>
        /// Initalise une nouvelle instance de <see cref="T:Black.SurfaceToolkit.Converters.AffineFunctionConverter" />.
        /// </summary>
        public AffineFunctionConverter()
            : base()
        {
        }

        #endregion

        #region Fonctions publiques

        /// <summary>
        /// Obtient l'abscisse de l'image spécifiée.
        /// </summary>
        /// <param name="p_dY">Image du point.</param>
        /// <returns>Abscisse de <paramref name="p_dY" />.</returns>
        /// <exception cref="T:System.InvalidOperationException">L'obtention de l'abscisse n'est pas possible.</exception>
        public override double GetAbscissa(double p_dY)
        {
            return ((p_dY - this.m_dYOrigin) / this.m_dSlope);
        }

        /// <summary>
        /// Obtient l'image de l'abscisse spécifiée.
        /// </summary>
        /// <param name="p_dX">Abscisse du point.</param>
        /// <returns>Image de <paramref name="p_dX" />.</returns>
        /// <exception cref="T:System.InvalidOperationException">L'obtention de l'image n'est pas possible.</exception>
        public override double GetImage(double p_dX)
        {
            return (this.m_dSlope * p_dX + this.m_dYOrigin);
        }

        #endregion

        #region Fonctions protégées

        /// <summary>
        /// Appelée lorsqu'un des points de contrôle change.
        /// </summary>
        protected override void OnControlPointsChanged()
        {
            double dY1 = Y1, y2 = Y2;
            double dX1 = X1, x2 = X2;

            this.m_dSlope = (dY1 - y2) / (dX1 - x2);
            this.m_dYOrigin = dY1 - (this.m_dSlope * dX1);
        }

        #endregion
    }
}
